/*
 * @brief:
 *      纱嘴对象，纱嘴的序号按照从１－８排列，与下位机相反
 *
 * ChangeLog        Author          Notes
 * 2015.08.29       Herbert         First Version
 */
#include "mhdef.h"
#include "yc.h"
#include "em_yc.h"
#include "ccycle.h"
#include <assert.h>
#include <malloc.h>
#include <string.h>
#include "stdio.h"
#include "timer.h"
#include <unistd.h>

#define YC_CYCLE_TIME   150
#define UP 1

YC* yc_new()
{
    int i = 0;
    YC *yc = (YC*)malloc(sizeof (YC));

    ccycle_init(&yc->cycle);
    ccycle_init(&yc->reset_cycle);

    timer_init(&yc->timer);

    for (i = 0; i < 4; i++)
    {
        yc->state[i] = 0xFF;
        yc->state_bk[i] = 0xFF;
    }

    yc->exec = emyc_exec;

    return yc;
}

void yc_set_cycle(YC *yc, CCYCLE *cycle, CCYCLE *reset_cycle)
{
    assert(yc != NULL);
    assert(cycle != NULL);
    assert(reset_cycle != NULL);

    memcpy(&yc->cycle, cycle, sizeof (CCYCLE));
    memcpy(&yc->reset_cycle, reset_cycle, sizeof (CCYCLE));
}

/*
 * @param yc: 纱嘴对象
 * @param type: 动作类型，动作或者复位
 * @param group: 组序号，从左机头到右机头从左往右依次为0-3
 * @param num: 纱嘴的组内序号0-7代表１－８号纱嘴
 */
int yc_exec(MH_UDP *pudp, YC *yc, ActType type, int group, int num)
{
    assert(yc != NULL);
    assert((group >= 0) && (group < 4));

    uchar state[4] = { 0 };
    int i = 0;
    if (type == RESET)
    {
        state[group] |= 0x01 << num;

        yc->state[group] |= 0x01 << num;
    }
    else
    {
        yc->state[group] ^= 0x01 << num;
        memcpy(state, yc->state, sizeof (state));
    }

    for (i = 0; i < 4; i++)
    {
        state[i] = yc_convert_state(yc, state[i]);
    }
    return yc->exec(pudp, type, state);
}

int yc_exec_group(MH_UDP *pudp, YC *yc, int group)
{
    assert(yc != NULL);
    assert((group >= 0) && (group < 4));
    int ret = -1;

    ActType type = ACT;
    uchar state[4] = { 0 };
    int i = 0;
    uchar group_state = yc_get_group_state(yc, group);
    if (group_state == UP)
    {
        for (i = 0; i < 8; i++)
        {
            yc->state[group] |= 1 << i;
            usleep(100000);
            memcpy(state, yc->state, sizeof (state));
            ret = yc->exec(pudp, type, state);
        }
    }
    else
    {
        for (i = 0; i < 8; i++)
        {
            yc->state[group] &= 0xfe << i;
            usleep(100000);
            memcpy(state, yc->state, sizeof (state));
            ret = yc->exec(pudp, type, state);
        }
    }

    for (i = 0; i < 4; i++)
    {
        state[i] = yc_convert_state(yc, state[i]);
    }
    return ret;
}

/*
 * @param yc: 纱嘴对象
 */
int yc_exec_cycle(MH_UDP *pudp, void *user_data)
{
    assert(user_data != NULL);
    YC *yc = (YC*)user_data;
    int group = -1;
    int index = -1;
    CCYCLE *cycle = NULL;
    ActType type = RESET;

    if (ccycle_get_state(&yc->reset_cycle) != CYCLE_STOP)
    {
        type = RESET;
        cycle = &yc->reset_cycle;
    }
    else if (ccycle_get_state(&yc->cycle) != CYCLE_STOP)
    {
        type = ACT;
        cycle = &yc->cycle;
    }

    if (cycle == NULL)
    {
        return 0;
    }

    group = cycle->group;
    index = cycle->index;

    if (ccycle_get_state(cycle) == CYCLE_READY)
    {
        ccycle_set_state(cycle, CYCLE_EXEC);
    }
    else
    {
        FEEDBACK fb;
        int ret = 0;
        memset(&fb, 0, sizeof (FEEDBACK));

        ret = feedback_get_error_state(pudp, &fb, (group > 1));

        if (ret < 0)
        {
            return ret;
        }

        ret = yc_encount_error(yc, &fb);

        if (ret < 0)
        {
            return ret;
        }

        ccycle_exec(cycle);

        if (type == RESET)
        {
            if (ccycle_complete(cycle))
            {
                ccycle_stop(cycle);
                if (ccycle_get_state(&yc->cycle) != CYCLE_STOP)
                {
              //      void timer_start(CHECK_TIMER *timer, short acc_time, short set_time, TIMEOUT_FUNC pfunc);
                    /* 执行动作循环 */
                    timer_start((CHECK_TIMER *)&yc->timer, 0, YC_CYCLE_TIME, yc_exec_cycle);
                }
                return 0;
            }
        }

        group = ccycle_get_group(cycle);
        index = ccycle_get_index(cycle);

    }

    if (group < 0 || index < 0)
    {
        return -1;
    }
    timer_start(&yc->timer, 0, YC_CYCLE_TIME, yc_exec_cycle);
    return yc_exec(pudp, yc, type, group, index);
}

int yc_get_next_diff(YC *yc, CCYCLE *cycle, int *group, int *index)
{
    assert(yc != NULL);
    assert(cycle != NULL);
    assert(group != NULL);
    assert(index != NULL);

    do
    {
        int filter = 0;
        ccycle_exec(cycle);

        if (ccycle_complete(cycle))
        {
            return FALSE;
        }

        *group = ccycle_get_group(cycle);
        *index = ccycle_get_index(cycle);

        filter = 0x01 << *index;
        if (((yc->state[*group] ^ yc->state_bk[*group]) & filter) == 0)
        {
            /* 状态相同 */
            continue;
        }

        break;
    } while (1);

    return TRUE;
}

int yc_restore(MH_UDP *pudp, void *user_data)
{
    assert(user_data != NULL);

    YC *yc = (YC*)user_data;
    int group = -1;
    int index = -1;
    CCYCLE *cycle = NULL;

    cycle = &yc->reset_cycle;

    if (ccycle_get_state(cycle) == CYCLE_STOP)
    {
        return 0;
    }


    if (ccycle_get_state(cycle) == CYCLE_READY)
    {
        int filter = 0;
        ccycle_set_state(cycle, CYCLE_EXEC);
        group = cycle->group;
        index = cycle->index;

        filter = 0x01 << index;

        if (((yc->state[group] ^ yc->state_bk[group]) & filter) == 0)
        {
            if (!yc_get_next_diff(yc, cycle, &group, &index))
            {
                ccycle_stop(cycle);
                return 0;
            }
        }
    }
    else
    {
        FEEDBACK fb;

        int ret = feedback_get_error_state(pudp, &fb, (group > 1));

        if (ret < 0)
        {
            return ret;
        }

        ret = yc_encount_error(yc, &fb);

        if (ret < 0)
        {
            return ret;
        }

        if (!yc_get_next_diff(yc, cycle, &group, &index))
        {
            ccycle_stop(cycle);
            return 0;
        }
    }

    if (group < 0 || index < 0)
    {
        return -1;
    }

    timer_start(&yc->timer, 0, YC_CYCLE_TIME, yc_restore);

    return yc_exec(pudp, yc, ACT, group, index);
}

/*
 * @note: 用于检测单个测试的错误
 */
int yc_check_error(MH_UDP *pudp, void *user_data)
{
    assert(user_data != NULL);
    YC *yc = (YC*)user_data;
    FEEDBACK fb;
    int ret = 0;
    int group = ccycle_get_group(&yc->cycle);

    memset(&fb, 0, sizeof (FEEDBACK));

    ret = feedback_get_error_state(pudp, &fb, (group > 1));
    if (ret < 0)
    {
        return ret;
    }

    return yc_encount_error(yc, &fb);
}

int yc_exec_timer(MH_UDP *pudp, YC *yc)
{
    assert(yc != NULL);
    return timer_exec(pudp, &yc->timer, (void*)yc);
}

/*
 * @param yc: 纱嘴对象，unused
 * @param state: 纱嘴状态
 * @note: 反转纱嘴状态
 */
uchar yc_convert_state(YC *yc, uchar state)
{
    uchar reverse_state = 0;
    int i = 0;
    for (i = 0; i < 8; i++)
    {
        int filter = 0x01 << i;
        uchar tmp = (state & filter) >> i;
        if (tmp == 1)
        {
            reverse_state |= tmp << (7 - i);
        }
    }

    return reverse_state;
}

/*
 * @param yc: 纱嘴对象
 * @param state: 从下位机读取到的纱嘴状态
 * @param size: state数组大小
 */
void yc_set_state(YC *yc, uchar *state, int size)
{
    assert(yc != NULL);
    assert(state != NULL);

    int i = 0;
    for (i = 0; i < size; i++)
    {
        yc->state[i] = yc_convert_state(yc, state[i]);
        yc->state_bk[i] = yc->state[i];

    }
}

/*
 * @param yc: 纱嘴对象
 * @param state[out]:获取到的纱嘴状态bit0-7代表１－８号纱嘴
 * @param size: state数组大小
 */
void yc_get_state(YC *yc, uchar *state, int size)
{
    assert(yc != NULL);
    assert(state != NULL);

    memcpy(state, yc->state, size);
}

void yc_set_group_state(YC *yc, uchar group_state, uchar group)
{
    assert(yc != NULL);

    yc->group_state[group] =  group_state;
}

uchar yc_get_group_state(YC *yc, uchar group)
{
    assert(yc != NULL);

    return yc->group_state[group];
}

void yc_stop_cycle(YC *yc)
{
    assert(yc != NULL);
    timer_stop(&yc->timer);
    ccycle_stop(&yc->reset_cycle);
    ccycle_stop(&yc->cycle);
}

/*
 * @note: 判断是否遇到错误
 */
int yc_encount_error(YC *yc, FEEDBACK *fb)
{
    if (fb != NULL)
    {
        if (fb->error.yc)
        {
            return CRGERROR_YC;
        }
    }
    return 0;
}

BOOL yc_reset_complete(YC *yc)
{
    assert(yc != NULL);

    return (ccycle_get_state(&yc->reset_cycle) == CYCLE_STOP);
}

void yc_start_timer(YC *yc, TIMEOUT_FUNC pfunc, BOOL now)
{
    assert(yc != NULL);
    if (now)
    {
        timer_start(&yc->timer, YC_CYCLE_TIME, YC_CYCLE_TIME, pfunc);
    }
    else
    {
        timer_start(&yc->timer, 0, YC_CYCLE_TIME, pfunc);
    }
}

CCYCLE* yc_get_cycle(YC *yc)
{
    assert(yc != NULL);
    return &yc->cycle;
}

BOOL yc_need_restore(YC *yc)
{
    assert(yc != NULL);
    return memcmp(yc->state, yc->state_bk, sizeof (yc->state));
}
